home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / dosrcss.zip / RCSEDIT.C < prev    next >
C/C++ Source or Header  |  1990-07-18  |  20KB  |  561 lines

  1. /*
  2.  *                     RCS stream editor
  3.  */
  4. #ifndef lint
  5. static char rcsid[]= "$Id: rcsedit.c,v 5.3 90/07/15 20:24:55 lfk Release $ Purdue CS";
  6. #endif
  7. /**********************************************************************************
  8.  *                       edits the input file according to a
  9.  *                       script from stdin, generated by diff -n
  10.  *                       performs keyword expansion
  11.  **********************************************************************************
  12.  */
  13.  
  14. /* Copyright (C) 1982, 1988, 1989 Walter Tichy
  15.    Distributed under license by the Free Software Foundation, Inc.
  16.  
  17. This file is part of RCS.
  18.  
  19. RCS is free software; you can redistribute it and/or modify
  20. it under the terms of the GNU General Public License as published by
  21. the Free Software Foundation; either version 1, or (at your option)
  22. any later version.
  23.  
  24. RCS is distributed in the hope that it will be useful,
  25. but WITHOUT ANY WARRANTY; without even the implied warranty of
  26. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  27. GNU General Public License for more details.
  28.  
  29. You should have received a copy of the GNU General Public License
  30. along with RCS; see the file COPYING.  If not, write to
  31. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  32.  
  33. Report problems and direct all questions to:
  34.  
  35.     rcs-bugs@cs.purdue.edu
  36.  
  37. */
  38.  
  39.  
  40. /* $Log:    rcsedit.c,v $
  41.  * Revision 5.3  90/07/15  20:24:55  lfk
  42.  * Most major fixes added between rev 5.1 and rev 5.5:
  43.  *     signals fixed so they work on MS-DOS
  44.  *     Added MKS arguments code so argv can be large
  45.  *     added code to handle slashes a'la Unix
  46.  *     added more file extensions to system from MS-DOS
  47.  * 
  48.  * Revision 5.2  90/07/15  11:33:29  ROOT_DOS
  49.  * DOS version of RCS 4.0 checked in for MODS
  50.  * by lfk@athena.mit.edu
  51.  * Also update to MSC 6.0
  52.  * 
  53.  * revision 5.2 koya 90/01/25 00:46:07
  54.  * Changed only path  name separators.
  55.  * 
  56.  * revision 5.1 koya 90/01/24 06:39:44
  57.  * Initial revision
  58.  * 
  59.  * Revision 4.8  89/05/01  15:12:35  narten
  60.  * changed copyright header to reflect current distribution rules
  61.  * 
  62.  * Revision 4.7  88/11/08  13:54:14  narten
  63.  * misplaced semicolon caused infinite loop
  64.  * 
  65.  * Revision 4.6  88/11/08  12:01:41  narten
  66.  * changes from  eggert@sm.unisys.com (Paul Eggert)
  67.  * 
  68.  * Revision 4.6  88/08/09  19:12:45  eggert
  69.  * Shrink stdio code size; allow cc -R.
  70.  * 
  71.  * Revision 4.5  87/12/18  11:38:46  narten
  72.  * Changes from the 43. version. Don't know the significance of the
  73.  * first change involving "rewind". Also, additional "lint" cleanup.
  74.  * (Guy Harris)
  75.  * 
  76.  * Revision 4.4  87/10/18  10:32:21  narten
  77.  * Updating version numbers. Changes relative to version 1.1 actually
  78.  * relative to 4.1
  79.  * 
  80.  * Revision 1.4  87/09/24  13:59:29  narten
  81.  * Sources now pass through lint (if you ignore printf/sprintf/fprintf 
  82.  * warnings)
  83.  * 
  84.  * Revision 1.3  87/09/15  16:39:39  shepler
  85.  * added an initializatin of the variables editline and linecorr
  86.  * this will be done each time a file is processed.
  87.  * (there was an obscure bug where if co was used to retrieve multiple files
  88.  *  it would dump)
  89.  * fix attributed to  Roy Morris @FileNet Corp ...!felix!roy
  90.  * 
  91.  * Revision 1.2  87/03/27  14:22:17  jenkins
  92.  * Port to suns
  93.  * 
  94.  * Revision 1.1  84/01/23  14:50:20  kcs
  95.  * Initial revision
  96.  * 
  97.  * Revision 4.1  83/05/12  13:10:30  wft
  98.  * Added new markers Id and RCSfile; added locker to Header and Id.
  99.  * Overhauled expandline completely() (problem with $01234567890123456789@).
  100.  * Moved trymatch() and marker table to rcskeys.c.
  101.  * 
  102.  * Revision 3.7  83/05/12  13:04:39  wft
  103.  * Added retry to expandline to resume after failed match which ended in $.
  104.  * Fixed truncation problem for $19chars followed by@@.
  105.  * Log no longer expands full path of RCS file.
  106.  * 
  107.  * Revision 3.6  83/05/11  16:06:30  wft
  108.  * added retry to expandline to resume after failed match which ended in $.
  109.  * Fixed truncation problem for $19chars followed by@@.
  110.  * 
  111.  * Revision 3.5  82/12/04  13:20:56  wft
  112.  * Added expansion of keyword Locker.
  113.  *
  114.  * Revision 3.4  82/12/03  12:26:54  wft
  115.  * Added line number correction in case editing does not start at the
  116.  * beginning of the file.
  117.  * Changed keyword expansion to always print a space before closing KDELIM;
  118.  * Expansion for Header shortened.
  119.  *
  120.  * Revision 3.3  82/11/14  14:49:30  wft
  121.  * removed Suffix from keyword expansion. Replaced fclose with ffclose.
  122.  * keyreplace() gets log message from delta, not from curlogmsg.
  123.  * fixed expression overflow in while(c=putc(GETC....
  124.  * checked nil printing.
  125.  *
  126.  * Revision 3.2  82/10/18  21:13:39  wft
  127.  * I added checks for write errors during the co process, and renamed
  128.  * expandstring() to xpandstring().
  129.  *
  130.  * Revision 3.1  82/10/13  15:52:55  wft
  131.  * changed type of result of getc() from char to int.
  132.  * made keyword expansion loop in expandline() portable to machines
  133.  * without sign-extension.
  134.  */
  135.  
  136.  
  137. #include "rcsbase.h"
  138.  
  139.  
  140. extern FILE * fopen();
  141. extern char * mktempfile();
  142. extern char * bindex();
  143. extern FILE * finptr, * frewrite;
  144. extern int rewriteflag;
  145. extern int nextc;
  146. extern char * RCSfilename, * workfilename;
  147. extern char * bindex();
  148. extern char * getfullRCSname();
  149. extern enum markers trymatch();
  150.  
  151.  
  152. FILE  * fcopy,  * fedit; /* result and edit file descriptors                */
  153. char  *resultfile;       /* result file name                                */
  154. char  * editfile;        /* edit   file name                                */
  155. int editline;  /*line counter in fedit; starts with 1, is always #lines+1   */
  156. int linecorr;  /*contains #adds - #deletes in each edit run.                */
  157.                /*used to correct editline in case file is not rewound after */
  158.                /* applying one delta                                        */
  159.  
  160. initeditfiles(dir)
  161. char * dir;
  162. /* Function: Initializes resultfile and editfile with temporary filenames
  163.  * in directory dir. Opens resultfile for reading and writing, with fcopy
  164.  * as file descriptor. fedit is set to nil.
  165.  */
  166. {
  167.     editline = linecorr = 0;    /* make sure we start from the beginning*/
  168.         resultfile=mktempfile(dir,TMPFILE1);
  169.         editfile  =mktempfile(dir,TMPFILE2);
  170.         fedit=nil;
  171.         if ((fcopy=fopen(resultfile,"w+"))==NULL) {
  172.                 faterror("Can't open working file %s",resultfile);
  173.         }
  174. }
  175.  
  176.  
  177. swapeditfiles(tostdout)
  178. /* Function: swaps resultfile and editfile, assigns fedit=fcopy,
  179.  * rewinds fedit for reading, and opens resultfile for reading and
  180.  * writing, using fcopy. If tostdout, fcopy is set to stdout.
  181.  */
  182. {       char * tmpptr;
  183.         if(ferror(fcopy))
  184.                 faterror("write failed on %s -- file system full?",resultfile);
  185.         fedit=fcopy;
  186.         rewind(fedit);
  187.         editline = 1; linecorr=0;
  188.         tmpptr=editfile; editfile=resultfile; resultfile=tmpptr;
  189.         if (tostdout)
  190.                 fcopy=stdout;
  191.         elsif ((fcopy=fopen(resultfile,"w+"))==NULL) {
  192.                 faterror("Can't open working file %s",resultfile);
  193.         }
  194. }
  195.  
  196.  
  197. finishedit(delta)
  198. struct hshentry * delta;
  199. /* copy the rest of the edit file and close it (if it exists).
  200.  * if delta!=nil, perform keyword substitution at the same time.
  201.  */
  202. {
  203.         register int c;
  204.         if (fedit!=nil) {
  205.                 if (delta!=nil) {
  206.                         while (expandline(fedit,fcopy,delta,false,false)) editline++;
  207.                 } else {
  208.                         while((c=getc(fedit))!=EOF) {
  209.                                 VOID putc(c,fcopy);
  210.                                 if (c=='\n') editline++;
  211.                         }
  212.                 }
  213.                 ffclose(fedit);
  214.         }
  215. }
  216.  
  217.  
  218. copylines(line,delta)
  219. register int line; struct hshentry * delta;
  220. /* Function: copies input lines editline..line-1 from fedit to fcopy.
  221.  * If delta != nil, keyword expansion is done simultaneously.
  222.  * editline is updated. Rewinds a file only if necessary.
  223.  */
  224. {
  225.  
  226.         if (editline>line) {
  227.                 /* swap files */
  228.                 finishedit((struct hshentry *)nil); swapeditfiles(false);
  229.                 /* assumes edit only during last pass, from the beginning*/
  230.         }
  231.         while (editline<line) {
  232.                 /*copy another line*/
  233.                 if (delta)
  234.                         VOID expandline(fedit,fcopy,delta,false,false);
  235.                 else
  236.                         while (putc(getc(fedit),fcopy)!='\n');
  237.                 editline++;
  238.         }
  239. }
  240.  
  241.  
  242.  
  243. xpandstring(delta)
  244. struct hshentry * delta;
  245. /* Function: Reads a string terminated by SDELIM from finptr and writes it
  246.  * to fcopy. Double SDELIM is replaced with single SDELIM.
  247.  * Keyword expansion is performed with data from delta.
  248.  * If rewriteflag==true, the string is also copied unchanged to frewrite.
  249.  * editline is updated.
  250.  */
  251. {
  252.         editline=1;
  253.         while (expandline(finptr,fcopy,delta,true,rewriteflag)) editline++;
  254.         nextc='\n';
  255. }
  256.  
  257.  
  258. copystring()
  259. /* Function: copies a string terminated with a single SDELIM from finptr to
  260.  * fcopy, replacing all double SDELIM with a single SDELIM.
  261.  * If rewriteflag==true, the string also copied unchanged to frewrite.
  262.  * editline is set to (number of lines copied)+1.
  263.  * Assumption: next character read is first string character.
  264.  */
  265. {    register c;
  266.     register FILE *fin, *frew, *fcop;
  267.     register write;
  268.  
  269.     fin=finptr; frew=frewrite; fcop=fcopy;
  270.         write=rewriteflag;
  271.         editline=1;
  272.         while ((c=GETC(fin,frew,write)) != EOF) {
  273.                 if ((c==SDELIM)&&((c=GETC(fin,frew,write)) != SDELIM)){
  274.                         /* end of string */
  275.                         nextc = c;
  276.                         return;
  277.                 }
  278.                 VOID putc(c,fcop);
  279.                 if (c=='\n') editline++;
  280.         }
  281.         nextc = c;
  282.         serror("Unterminated string");
  283.         return;
  284. }
  285.  
  286.  
  287.  
  288.  
  289. editstring(delta)
  290. struct hshentry * delta;
  291. /* Function: reads an edit script from finptr and applies it to
  292.  * file fedit; the result is written to fcopy.
  293.  * If delta!=nil, keyword expansion is performed simultaneously.
  294.  * If frewrite==true, the edit script is also copied verbatim to frewrite.
  295.  * Assumes that all these files are open.
  296.  * If running out of lines in fedit, fedit and fcopy are swapped.
  297.  * resultfile and editfile are the names of the files that go with fcopy
  298.  * and fedit, respectively.
  299.  * Assumes the next input character from finptr is the first character of
  300.  * the edit script. Resets nextc on exit.
  301.  */
  302. {
  303.         int ed; /* editor command */
  304.         register int c;
  305.     register FILE *fin, *frew;
  306.         register int write, i;
  307.         int line, length;
  308.  
  309.     fin=finptr;  frew=frewrite;
  310.         editline += linecorr; linecorr=0; /*correct line number*/
  311.         write=rewriteflag;
  312.         for (;;) {
  313.                 /* read next command and decode */
  314.                 /* assume next non-white character is command name*/
  315.                 while((ed=GETC(fin,frew,write))=='\n'||
  316.                         ed==' ' || ed=='\t');
  317.                 if (ed==SDELIM) break;
  318.                 /* now attempt to read numbers. */
  319.                 /* fscanf causes trouble because of the required echoing */
  320.                 while ((c=GETC(fin,frew,write))==' ');  /*skip spaces*/
  321.                 if (!('0'<=c && c<='9')) {
  322.                         faterror("missing line number in edit script");
  323.                         break;
  324.                 }
  325.                 line= c -'0';
  326.                 while ('0'<=(c=GETC(fin,frew,write)) && c<='9') {
  327.                         line = line*10 + c-'0';
  328.                 }
  329.                 while (c==' ') c=GETC(fin,frew,write);
  330.                 if (!('0'<=c && c<='9')) {
  331.                         faterror("incorrect range in edit script");
  332.                         break;
  333.                 }
  334.                 length= c -'0';
  335.                 while ('0'<=(c=GETC(fin,frew,write)) && c<='9') {
  336.                         length = length*10 + c-'0';
  337.                 }
  338.                 while(c!='\n'&&c!=EOF) c=GETC(fin,frew,write); /* skip to end of line */
  339.  
  340.                 switch (ed) {
  341.                 case 'd':
  342.                         copylines(line,delta);
  343.                         /* skip over unwanted lines */
  344.                         for (i=length;i>0;i--) {
  345.                                 /*skip next line*/
  346.                                 while ((c=getc(fedit))!='\n')
  347.                     if (c==EOF)
  348.                         faterror("EOF during edit");
  349.                                 editline++;
  350.                         }
  351.                         linecorr -= length;
  352.                         break;
  353.                 case 'a':
  354.                         copylines(line+1,delta); /*copy only; no delete*/
  355.                         for (i=length;i>0;i--) {
  356.                                 /*copy next line from script*/
  357.                                 if (delta!=nil)
  358.                                        VOID expandline(fin,fcopy,delta,true,write);
  359.                                 else {
  360.                                        c = GETC(fin,frew,write);
  361.                                        while (putc(c,fcopy)!='\n'){
  362.                                                if ((c==SDELIM)&&((c=GETC(fin,frew,write))!=SDELIM)){
  363.                                                        serror("Missing string delimiter in edit script");
  364.                                                        VOID putc(c,fcopy);
  365.                                                }
  366.                                                c = GETC(fin,frew,write);
  367.                                        }
  368.                                 }
  369.                         }
  370.                         linecorr += length;
  371.                         break;
  372.                 default:
  373.                         faterror("unknown command in edit script: %c", ed);
  374.                         break;
  375.                 }
  376.         }
  377.         nextc=GETC(fin,frew,write);
  378. }
  379.  
  380.  
  381.  
  382. /* The rest is for keyword expansion */
  383.  
  384.  
  385.  
  386. expandline(in, out, delta,delimstuffed,write)
  387. register FILE * in, * out; struct hshentry * delta;
  388. int delimstuffed, write;
  389. /* Function: Reads a line from in and writes it to out.
  390.  * If delimstuffed==true, double SDELIM is replaced with single SDELIM.
  391.  * Keyword expansion is performed with data from delta.
  392.  * If write==true, the string is also copied unchanged to frewrite.
  393.  * Returns false if end-of-string or end-of-line is detected, true otherwise.
  394.  */
  395. {
  396.     register c;
  397.     register FILE * frew;
  398.     register w, ds;
  399.     register char * tp;
  400.     char keystring[keylength+2];
  401.     char keyval[keyvallength+2];
  402.         enum markers matchresult;
  403.  
  404.     frew = frewrite;
  405.     w = write;
  406.     ds = delimstuffed;
  407.     c=GETC(in,frew,w);
  408.         for (;;) {
  409.                 if (c==EOF) {
  410.                         if(ds) {
  411.                                 error("unterminated string");
  412.                                 nextc=c;
  413.                         }
  414.                         return(false);
  415.                 }
  416.  
  417.                 if (c==SDELIM && ds) {
  418.                         if ((c=GETC(in,frew,w))!=SDELIM) {
  419.                                 /* end of string */
  420.                                 nextc=c;
  421.                                 return false;
  422.                         }
  423.                 }
  424.                 VOID putc(c,out);
  425.  
  426.                 if (c=='\n') return true; /* end of line */
  427.  
  428.         if (c==KDELIM) {
  429.                         /* check for keyword */
  430.                         /* first, copy a long enough string into keystring */
  431.             tp=keystring;
  432.             while (((c=GETC(in,frew,w))!=EOF) && (tp<keystring+keylength) && (c!='\n')
  433.                    && (c!=SDELIM) && (c!=KDELIM) && (c!=VDELIM)) {
  434.                               VOID putc(c,out);
  435.                   *tp++ = c;
  436.                         }
  437.             *tp++ = c; *tp = '\0';
  438.             matchresult=trymatch(keystring,false);
  439.             if (matchresult==Nomatch) continue;
  440.             /* last c will be dealt with properly by continue*/
  441.  
  442.             /* Now we have a keyword terminated with a K/VDELIM */
  443.             if (c==VDELIM) {
  444.                   /* try to find closing KDELIM, and replace value */
  445.                   tp=keyval;
  446.                   while (((c=GETC(in,frew,w)) != EOF)
  447.                      && (c!='\n') && (c!=KDELIM) && (tp<keyval+keyvallength)) {
  448.                       *tp++ =c;
  449.                       if (c==SDELIM && ds) { /*skip next SDELIM */
  450.                         c=GETC(in,frew,w);
  451.                         /* Can't be at end of string.
  452.                         /* always a \n before closing SDELIM */
  453.                       }
  454.                   }
  455.                   if (c!=KDELIM) {
  456.                     /* couldn't find closing KDELIM -- give up */
  457.                     VOID putc(VDELIM,out); *tp='\0';
  458.                     VOID fputs(keyval,out);
  459.                     continue;   /* last c handled properly */
  460.                   }
  461.             }
  462.             /* now put out the new keyword value */
  463.             keyreplace(matchresult,delta,out);
  464.                 }
  465.                 c=GETC(in,frew,w);
  466.         } /* end for */
  467. }
  468.  
  469.  
  470.  
  471. keyreplace(marker,delta,out)
  472. enum markers marker; struct hshentry * delta; register FILE * out;
  473. /* function: ouputs the keyword value(s) corresponding to marker.
  474.  * Attributes are derived from delta.
  475.  */
  476. {
  477.         char * date;
  478.         register char * sp;
  479.  
  480.         date= delta->date;
  481.  
  482.         switch (marker) {
  483.         case Author:
  484.                 VOID fprintf(out,"%c %s %c",VDELIM,delta->author,KDELIM);
  485.                 break;
  486.         case Date:
  487.                 VOID putc(VDELIM,out);VOID putc(' ',out);
  488.                 VOID PRINTDATE(out,date);VOID putc(' ',out);
  489.                 VOID PRINTTIME(out,date);VOID putc(' ',out);VOID putc(KDELIM,out);
  490.                 break;
  491.         case Id:
  492.     case Header:
  493.         VOID putc(VDELIM,out); VOID putc(' ',out);
  494.         if (marker==Id)
  495. #ifdef MSDOS
  496. #    ifdef MKS
  497.              VOID fputs(bindex(RCSfilename,'/'),out);
  498. #    else
  499.              VOID fputs(bindex(RCSfilename,'\\'),out);
  500. #    endif
  501. #else
  502.              VOID fputs(bindex(RCSfilename,'/'),out);
  503. #endif /* MSDOS */
  504.         else     VOID fputs(getfullRCSname(),out);
  505.         VOID fprintf(out," %s ", delta->num);
  506.                 VOID PRINTDATE(out,date);VOID putc(' ',out);VOID PRINTTIME(out,date);
  507.         VOID fprintf(out, " %s %s ",delta->author,delta->state);
  508.         if (delta->lockedby!=nil)
  509.              VOID fprintf(out,"Locker: %s ",delta->lockedby);
  510.         VOID putc(KDELIM,out);
  511.                 break;
  512.         case Locker:
  513.                 VOID fprintf(out,"%c %s %c", VDELIM,
  514.                         delta->lockedby==nil?"":delta->lockedby,KDELIM);
  515.                 break;
  516.         case Log:
  517.                 VOID fprintf(out, "%c\t%s %c\n%sRevision %s  ",
  518. #ifdef MSDOS
  519. #    ifdef MKS
  520.                         VDELIM, bindex(RCSfilename,'/'), KDELIM, Comment, delta->num);
  521. #    else
  522.                         VDELIM, bindex(RCSfilename,'\\'), KDELIM, Comment, delta->num);
  523. #    endif                        
  524. #else
  525.                         VDELIM, bindex(RCSfilename,'/'), KDELIM, Comment, delta->num);
  526. #endif /* MSDOS */
  527.                 VOID PRINTDATE(out,date);VOID fputs("  ",out);VOID PRINTTIME(out,date);
  528.                 VOID fprintf(out, "  %s\n%s",delta->author,Comment);
  529.                 /* do not include state here because it may change and is not updated*/
  530.                 sp = delta->log;
  531.                 while (*sp) if (putc(*sp++,out)=='\n') VOID fputs(Comment,out);
  532.                 /* Comment is the comment leader */
  533.                 break;
  534.         case RCSfile:
  535. #ifdef MSDOS
  536. #    ifdef MKS
  537.                 VOID fprintf(out,"%c %s %c",VDELIM,bindex(RCSfilename,'/'),KDELIM);
  538. #    else
  539.                 VOID fprintf(out,"%c %s %c",VDELIM,bindex(RCSfilename,'\\'),KDELIM);
  540. #    endif                        
  541. #else
  542.                 VOID fprintf(out,"%c %s %c",VDELIM,bindex(RCSfilename,'/'),KDELIM);
  543. #endif /* MSDOS */
  544.                 break;
  545.         case Revision:
  546.                 VOID fprintf(out,"%c %s %c",VDELIM,delta->num,KDELIM);
  547.                 break;
  548.         case Source:
  549.                 VOID fprintf(out,"%c %s %c",VDELIM,getfullRCSname(),KDELIM);
  550.                 break;
  551.         case State:
  552.                 VOID fprintf(out,"%c %s %c",VDELIM,delta->state,KDELIM);
  553.                 break;
  554.         case Nomatch:
  555.                 VOID putc(KDELIM,out);
  556.                 break;
  557.         }
  558. }
  559.  
  560.  
  561.